/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月30日
 */
package com.massyframework.beanskin.runtime.framework.installing;

import java.io.File;
import java.net.URL;
import java.util.List;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.massyframework.beanskin.ModuleRuntimeException;
import com.massyframework.beanskin.RequireLibraryDescriptor;
import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.util.exceptioncollect.ExceptionCollectUtils;
import com.massyframework.beanskin.util.localstore.LocalStore;
import com.massyframework.beanskin.util.variables.StringVariableReplacer;
import com.massyframework.beanskin.util.version.VersionRange;

/**
 * 依赖类库解析
 * 
 * @author huangkh
 *
 */
public abstract class RequireLibraryModuleParser<B> extends ModuleIdentifierModuleParser<B> {

	protected static final String REQUIRES = "requires";
	protected static final String LIBRARY = "library";
	protected static final String VERSION_RANGE = "version-range";
	protected static final String TRANSITIVE = "transitive";

	protected static final String EXTENDS = "extends";
	private static final String FILENAME = "requires.json";

	private boolean parsed = false;
	/**
	 * 构造方法
	 * 
	 * @param kernel     {@link Assembly},内核装配件
	 * @param localStore (@link LocalStore},本地存储
	 */
	public RequireLibraryModuleParser(Assembly kernel, LocalStore localStore) {
		super(kernel, localStore);
	}

	@Override
	protected void doParseNode(Node node, Expression<String> expression, StringVariableReplacer replacer, B builder) {
		if (node.getNodeName().equals(REQUIRES)) {
			this.doParseRequires(node.getChildNodes(), builder);
		}
		
		if (!this.parsed) {
				this.parsed = true;
			// 加载外置的依赖库
			String name = EXTENDS.concat(File.separator).concat(FILENAME);
			File file = this.getLocalStore().getDeploymentDirectory(this.getModuleIdentifier()).resolve(name).toFile();
			if (file.exists()) {
				try {
					URL url = file.toURI().toURL();
					RequiresJsonParser parser = new RequiresJsonParser();
					List<RequireLibraryDescriptor> requires = parser.parserRequireLibraries(url);
					for (RequireLibraryDescriptor descriptor : requires) {
						this.addRequriedLibrary(descriptor, builder);
					}
				} catch (Exception e) {
					ModuleRuntimeException re = new ModuleRuntimeException(this.getModuleIdentifier(), e);
					ExceptionCollectUtils.addException(re);
				}
			}
		}
	}

	/**
	 * 解析所有依赖
	 * 
	 * @param nodes   {@link NodeList}
	 * @param builder {@link B}
	 */
	protected void doParseRequires(NodeList nodes, B builder) {
		int size = nodes.getLength();
		for (int i = 0; i < size; i++) {
			Node node = nodes.item(i);
			if (node.getNodeName().equals(LIBRARY)) {
				this.doParseRequireLibrary(node, builder);
			}
		}
	}

	/**
	 * 解析依赖类库
	 * 
	 * @param node
	 * @param builder
	 */
	protected void doParseRequireLibrary(Node node, B builder) {
		String groupId = this.getTextContent(node.getAttributes().getNamedItem(GROUPID));
		String moduleId = this.getTextContent(node.getAttributes().getNamedItem(MODULEID));

		VersionRange versionRange = VersionRange.EMPTY;
		Node versionRangeNode = node.getAttributes().getNamedItem(VERSION_RANGE);
		if (versionRangeNode != null) {
			versionRange = VersionRange.valueOf(this.getTextContent(versionRangeNode));
		}

		boolean transitive = false;
		Node transitiveNode = node.getAttributes().getNamedItem(TRANSITIVE);
		if (transitiveNode != null) {
			transitive = Boolean.parseBoolean(this.getTextContent(transitiveNode));
		}

		RequireLibraryDescriptor descriptor = RequireLibraryDescriptor.newBuilder().groupId(groupId).moduleId(moduleId)
				.versionRange(versionRange).transitive(transitive).build();
		this.addRequriedLibrary(descriptor, builder);
	}

	/**
	 * 添加依赖类库
	 * 
	 * @param descriptor {@link RequireLibraryDescriptor}
	 * @param builder    {@link B}
	 */
	protected abstract void addRequriedLibrary(RequireLibraryDescriptor descriptor, B builder);

}
